﻿using SuperFrame.Charts.Modes;
using Microsoft.Expression.Shapes;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;

namespace SuperFrame.Charts
{
    public class PieChart : Viewbox
    {
        public PieChart()
            : base()
        {
            this.Stretch = Stretch.Uniform;
            rootPanel = new Canvas();
            this.Child = rootPanel;
            rootPanel.Margin = new Thickness(10);
            this.Loaded += PieChart_Loaded;
        }

        void PieChart_Loaded(object sender, RoutedEventArgs e)
        {
            if (!_isLoaded)//加一个属性判断 防止重复加载
            {
                rootPanel.Width = Radius * 3.3;
                rootPanel.Height = Radius * 3.5;
                _isLoaded=true;
            }
        }
        private delegate void RefreshDataValueDeleget(List<IntervalMode> value);

        #region Propertys
        private Canvas rootPanel = null;
        private bool _isLoaded=false;
        private double radius = 50;
        /// <summary>
        /// 圆弧半径
        /// </summary>
        public double Radius
        {
            get { return radius; }
            set
            {
                if (value >= 0)
                {
                    radius = value;
                }
                else
                {
                    throw new Exception("圆弧半径不能为负数！");
                }
            }
        }

        private Brush defautClolor = new SolidColorBrush(Colors.Red);

        public Brush DefautClolor
        {
            get { return defautClolor; }
            set { defautClolor = value; }
        }
        /// <summary>
        /// 形状
        /// Pie--饼状
        /// RingRatio-环状
        /// </summary>
        public PieType PieType { get; set; }

        private Brush foreground = new SolidColorBrush(Colors.Gray);
        /// <summary>
        /// 前景色
        /// </summary>
        public Brush Foreground
        {
            get { return foreground; }
            set { foreground = value; }
        }
        private double lableFontSize = -1;
        /// <summary>
        /// 刻度标签字号
        /// </summary>
        public double LableFontSize
        {
            get
            {
                if (lableFontSize == -1)
                    return Radius * 0.1;
                return lableFontSize;
            }
            set
            {
                try
                {
                    lableFontSize = value;
                }
                catch
                {
                    lableFontSize = -1;
                }
            }
        }
        #endregion

        void DrawControls()
        {

            rootPanel.Children.Clear();
            //计算每个模块所占的比率
            if (DataValue != null && DataValue.Count > 0)
            {
                double tatolValue = DataValue.Select(c => c.Value).Sum();
                double unitAngel = 360 / tatolValue;
                double startAngle = 0;
                double endAngle = 360;
                List<IntervalMode> modeList = new List<IntervalMode>();
                for (int i = 0; i < DataValue.Count; i++)
                {
                    #region 根据比例画弧

                    string valueInfo = Math.Round(100 * DataValue[i].Value / tatolValue, 2).ToString() + "%";
                    endAngle = startAngle + unitAngel * DataValue[i].Value;
                    double angle = startAngle + unitAngel * DataValue[i].Value / 2;//每个模块的角度位置
                    Arc arc = new Arc();
                    arc.Height = Radius * 2;
                    arc.Width = Radius * 2;
                    arc.Fill = DataValue[i].ColorValue;
                    if (PieType == PieType.Pie)
                    {
                        arc.ArcThickness = Radius;
                    }
                    else
                    {
                        arc.ArcThickness = Radius / 2;
                    }
                    arc.Stretch = Stretch.None;
                    arc.StartAngle = startAngle;
                    arc.EndAngle = endAngle;
                    double tagValue = startAngle == 0 ? unitAngel * DataValue[i].Value / 2 : angle;
                    arc.Tag = tagValue + ":" + "1";
                    arc.PreviewMouseLeftButtonDown += arc_PreviewMouseLeftButtonDown;
                    //Canvas.SetLeft(arc, Radius / 2);
                    //Canvas.SetTop(arc, Radius / 2);
                    arc.SetValue(Canvas.TopProperty, Radius / 2);
                    arc.SetValue(Canvas.LeftProperty, Radius / 2);
                    rootPanel.Children.Add(arc);
                    startAngle = endAngle;
                    #endregion

                    #region 画线

                    Point innerLinStartPoint = GetPointByValue(angle, 0.75 * Radius);
                    Point innerLinEndPoint = GetPointByValue(angle, 1.25 * Radius);
                    Point outLinEndPoint = new Point();
                    if (0 < angle && angle <= 180)
                    {
                        outLinEndPoint.X = innerLinEndPoint.X + 0.4 * Radius;
                        outLinEndPoint.Y = innerLinEndPoint.Y;
                    }
                    else
                    {
                        outLinEndPoint.X = innerLinEndPoint.X - 0.4 * Radius;
                        outLinEndPoint.Y = innerLinEndPoint.Y;

                    }

                    Line line = new Line();
                    line.Stroke = Foreground;
                    line.StrokeThickness = 0.02 * Radius;
                    line.X1 = innerLinStartPoint.X;
                    line.Y1 = innerLinStartPoint.Y;
                    line.X2 = innerLinEndPoint.X;
                    line.Y2 = innerLinEndPoint.Y;
                    rootPanel.Children.Add(line);

                    Line line2 = new Line();
                    line2.Stroke = Foreground;
                    line2.StrokeThickness = 0.02 * Radius;
                    line2.X1 = innerLinEndPoint.X;
                    line2.Y1 = innerLinEndPoint.Y;
                    line2.X2 = outLinEndPoint.X;
                    line2.Y2 = outLinEndPoint.Y;
                    rootPanel.Children.Add(line2);
                    #endregion

                    #region 加提示信息
                    // 线上信息
                    TextBlock tb = new TextBlock() { Text = valueInfo, Height = 0.15 * Radius, Width = 0.5 * Radius, Foreground = Foreground, FontSize = LableFontSize };
                    if (0 < angle && angle < 180)
                    {
                        tb.SetValue(Canvas.LeftProperty, innerLinEndPoint.X);
                        tb.SetValue(Canvas.TopProperty, innerLinEndPoint.Y - tb.Height);
                    }
                    else
                    {
                        tb.SetValue(Canvas.LeftProperty, outLinEndPoint.X);
                        tb.SetValue(Canvas.TopProperty, outLinEndPoint.Y - tb.Height);
                    }
                    rootPanel.Children.Add(tb);
                    //线下信息
                    TextBlock tbInfo = new TextBlock() { Text = DataValue[i].Msg, Height = 0.15 * Radius, Width = 0.5 * Radius, Foreground = Foreground, FontSize = LableFontSize };
                    if (0 < angle && angle < 180)
                    {
                        tbInfo.SetValue(Canvas.LeftProperty, innerLinEndPoint.X);
                        tbInfo.SetValue(Canvas.TopProperty, innerLinEndPoint.Y);
                    }
                    else
                    {
                        tbInfo.SetValue(Canvas.LeftProperty, outLinEndPoint.X);
                        tbInfo.SetValue(Canvas.TopProperty, outLinEndPoint.Y);
                    }
                    rootPanel.Children.Add(tbInfo);
                    #endregion

                    modeList.Add(new IntervalMode()
                    {
                        ColorValue = DataValue[i].ColorValue,
                        Msg = DataValue[i].Msg
                    });
                }
                //添加一个图例信息
                LegendControl legent = new LegendControl();
                legent.Width = 3 * Radius;
                legent.Height = 0.6 * Radius;
                legent.Foreground = Foreground;
                legent.FontSize = LableFontSize;
                legent.LegentInfoList = modeList;
                legent.SetValue(Canvas.TopProperty, 3 * Radius);
                legent.SetValue(Canvas.LeftProperty, 0d);
                rootPanel.Children.Add(legent);
            }
        }
        /// <summary>
        /// 圆弧上的鼠标点击事件 实现饼状分离的效果
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void arc_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Arc arc = sender as Arc;
            if (arc != null && !string.IsNullOrWhiteSpace(arc.Tag.ToString()))
            {
                string[] arr = arc.Tag.ToString().Split(':');
                if (arr.Length < 2) return;
                if (arr[1] == "1")
                {

                    double angel = double.Parse(arr[0]);
                    double x = 0;
                    double y = 0;
                    if (0 < angel && angel <= 90)
                    {
                        x = Radius / 2 + Math.Sin(Math.PI * angel / 180.0) * Radius / 10;
                        y = Radius / 2 - Math.Cos(Math.PI * angel / 180.0) * Radius / 10;
                    }
                    else if (90 < angel && angel <= 180)
                    {
                        x = Radius / 2 + Math.Abs(Math.Sin(Math.PI * angel / 180.0) * Radius / 10);
                        y = Radius / 2 + Math.Abs(Math.Cos(Math.PI * angel / 180.0) * Radius / 10);
                    }
                    else if (180 < angel && angel <= 270)
                    {
                        x = Radius / 2 - Math.Abs(Math.Sin(Math.PI * angel / 180.0) * Radius / 10);
                        y = Radius / 2 + Math.Abs(Math.Cos(Math.PI * angel / 180.0) * Radius / 10);
                    }
                    else
                    {
                        x = Radius / 2 - Math.Abs(Math.Sin(Math.PI * angel / 180.0) * Radius / 10);
                        y = Radius / 2 - Math.Abs(Math.Cos(Math.PI * angel / 180.0) * Radius / 10);
                    }
                    arc.Tag = arr[0] + ":" + "0";
                    arc.SetValue(Canvas.LeftProperty, x);
                    arc.SetValue(Canvas.TopProperty, y);
                }
                else
                {
                    arc.Tag = arr[0] + ":" + "1";
                    arc.SetValue(Canvas.LeftProperty, Radius / 2);
                    arc.SetValue(Canvas.TopProperty, Radius / 2);
                }
            }
        }
        /// <summary>
        /// 获取坐标点
        /// </summary>
        /// <param name="angel"></param>
        /// <returns></returns>
        private Point GetPointByValue(double angle, double radiusValue)
        {
            Point center = new Point(Radius * 1.5, Radius * 1.5);//获取圆心坐标
            Point point = new Point();
            angle = angle * Math.PI / 180;
            point.X = center.X + radiusValue * Math.Sin(angle);
            point.Y = center.Y - radiusValue * Math.Cos(angle);
            return point;
        }


        public List<IntervalMode> DataValue
        {
            get { return (List<IntervalMode>)GetValue(DataValueProperty); }
            set { SetValue(DataValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataValueProperty =
            DependencyProperty.Register("DataValue", typeof(List<IntervalMode>), typeof(PieChart), new PropertyMetadata(null, new PropertyChangedCallback(CurrentValuePropertychanged)));

        private static void CurrentValuePropertychanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            PieChart basecontrol = obj as PieChart;
            if (basecontrol != null)
                basecontrol.Dispatcher.Invoke(new RefreshDataValueDeleget(basecontrol.RefreshDataValue), e.NewValue);
        }

         void RefreshDataValue(List<IntervalMode> value)
        {
            DrawControls();
        }
    }
}
